package top.saplf.library.ui

import android.content.Context
import android.support.design.widget.FloatingActionButton
import android.util.AttributeSet
import android.view.View
import android.view.View.MeasureSpec.EXACTLY
import android.view.View.MeasureSpec.makeMeasureSpec
import android.view.ViewGroup
import top.saplf.library.R
import top.saplf.library.ext.forEach
import top.saplf.library.ext.use

/**
 * @author Saplf
 */
class FloatingActionMenu : ViewGroup {

    private val container: Array<MutableList<View>> by lazy {
        Array(5) { mutableListOf<View>() }
    }
    /**
     * 控制按钮的位置
     */
    private val actionPosition: IntArray by lazy { IntArray(2) }
    private val fabSize: Int by lazy { context.resources.getDimensionPixelSize(R.dimen.design_fab_size_normal) }
    private val fabIntent: Int by lazy { context.resources.getDimensionPixelSize(R.dimen.fab_intent) }
    private val placeWidth: Int by lazy { fabSize + fabIntent * 2 }

    var showAction: (() -> Unit)? = null
    var hideAction: (() -> Unit) ? = null
    private var showMenu: Boolean = false

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    override fun onViewAdded(child: View) {
        super.onViewAdded(child)
        val layoutParam = child.layoutParams as LayoutParams
        if (layoutParam.align == LayoutParams.CENTER) {
            child.visibility = View.VISIBLE
            child.setOnClickListener {
                if (showMenu) {
                    hideMenu()
                } else {
                    showMenu()
                }
            }
        } else {
            child.visibility = View.GONE
        }
    }

    override fun onViewRemoved(child: View) {
        super.onViewRemoved(child)
        val lp = child.layoutParams as LayoutParams
        container[lp.align].remove(child)
    }

    fun hideMenu() {
        if (!showMenu) return
        showMenu = false
        hideAction?.invoke()
        forEach {
            if (it !in container[LayoutParams.CENTER] && it is FloatingActionButton) {
                it.hide()
            }
        }
    }

    fun showMenu() {
        if (showMenu) return
        showMenu = true
        showAction?.invoke()
        forEach {
            if (it !in container[LayoutParams.CENTER] && it is FloatingActionButton) {
                it.show()
            }
        }
    }

    override fun generateLayoutParams(attrs: AttributeSet): ViewGroup.LayoutParams
            = LayoutParams(context, attrs)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        (0 until container.size).forEach { container[it].clear() }
        forEach {
            val layoutParam = it.layoutParams as LayoutParams
            container[layoutParam.align].add(it)
            measureChild(it, widthMeasureSpec, heightMeasureSpec)
        }
        actionPosition[0] = container[3].size * placeWidth
        actionPosition[1] = container[0].size * placeWidth
        val verticalCount = container[0].size + container[2].size + 1
        val horizontalCount = container[1].size + container[3].size + 1
        setMeasuredDimension(
                makeMeasureSpec(horizontalCount * placeWidth, EXACTLY),
                makeMeasureSpec(verticalCount * placeWidth, EXACTLY)
        )
        calculatePosition()
    }

    private fun calculatePosition() {
        val ol = actionPosition[0] + fabIntent
        val ot = actionPosition[1] + fabIntent
        forEach {
            with(it.layoutParams as LayoutParams) {
                val list = container[align]
                val index = list.indexOf(it) + 1
                val offset = index * placeWidth
                when (align) {
                    LayoutParams.TOP -> {
                        left = ol
                        top = ot - offset
                    }
                    LayoutParams.RIGHT -> {
                        left = ol + offset
                        top = ot
                    }
                    LayoutParams.BOTTOM -> {
                        left = ol
                        top = ot + offset
                    }
                    LayoutParams.LEFT -> {
                        left = ol - offset
                        top = ot
                    }
                    LayoutParams.CENTER -> {
                        left = ol
                        top = ot
                    }
                }
            }
        }
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        forEach {
            with(it.layoutParams as LayoutParams) {
                it.layout(left, top, left + fabSize, top + fabSize)
            }
        }
    }

    fun hide() {
        container[LayoutParams.CENTER]
                .takeIf { it.size == 1 }
                ?.forEach { (it as FloatingActionButton).hide() }
    }

    fun show() {
        container[LayoutParams.CENTER]
                .takeIf { it.size == 1 }
                ?.forEach { (it as FloatingActionButton).show() }
    }

    class LayoutParams : ViewGroup.LayoutParams {

        constructor(towards: Int = TOP): super(WRAP_CONTENT, WRAP_CONTENT) {
            align = towards
        }

        constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
            attrs.use(context, R.styleable.FloatingActionMenu_Layout) {
                align = getInt(R.styleable.FloatingActionMenu_Layout_fam_towards, TOP)
            }
        }

        companion object {
            val TOP = 0x00
            val RIGHT = 0x01
            val BOTTOM = 0x02
            val LEFT = 0x03
            val CENTER = 0x04
        }

        var align: Int = CENTER

        var left: Int = 0
        var top: Int = 0
    }
}